package com.service.user;

import com.domain.HttpResponse;
import com.domain.ex.BizException;
import com.domain.ex.Codes;
import com.domain.myenum.RoleEnum;
import com.domain.page.Paginator;
import com.dto.UserExtDto;
import com.dto.UserSortDto;
import com.dto.statistic.ConsumptionWaterDto;
import com.dto.statistic.StatisticOutputDto;
import com.dto.statistic.UserStatisticDto;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.handler.email.Email;
import com.handler.email.EmailHandler;
import com.mapper.self.CompanyMapper;
import com.mapper.self.IncomeWaterMapper;
import com.mapper.self.OrderMapper;
import com.mapper.self.SetMapper;
import com.pojo.ShCompany;
import com.pojo.ShIncomeWater;
import com.pojo.ShSet;
import com.utils.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Huoyunren on 2016/1/27.
 */
@Service
public class UserServiceImpl implements UserService {

  @Autowired
  private CompanyMapper companyMapper;
  @Autowired
  private Gson gson;
  @Autowired
  private EmailHandler emailHandler;
  @Autowired
  private IncomeWaterMapper incomeWaterMapper;
  @Autowired
  private OrderMapper orderMapper;
  @Autowired
  private SetMapper setMapper;

  // - 注册
  @Override
  public Object register(String email, String referralCode) {
    if (!ValidatorUtils.validatorEmail(email)) {
      throw BizException.create(Codes.SystemDeclare, "邮箱格式错误");
    }
    ShCompany shCompany = companyMapper.queryByEmail(email);
    if (shCompany != null) {
      throw BizException.create(Codes.SystemDeclare, "邮箱已被注册");
    }
    List<String> codes = companyMapper.queryCodes();
    if (StringUtils.isNotBlank(referralCode)) {
      // - 有推荐人邀请码
      if (!isReferralCodeExists(referralCode, codes)) {
        throw BizException.create(Codes.SystemDeclare, "邀请码不存在");
      }
    }
    String password = RandomUtils.random4();
    String code = getUniqueUnUsedReferralCode(RandomUtils.random6(), codes);
    companyMapper.register(email, EncryptUtils.md5(password), DateUtils.currentDate(), code, referralCode);
    // - 异步发邮件 - 发送初始密码
    Email e = new Email();
    String[] to = new String[1];
    to[0] = email;
    e.setTo(to);
    e.setSubject("注册成功");
    e.setEnableHtml(Boolean.FALSE);
    StringBuffer sb = new StringBuffer();
    sb.append("初始密码：" + password + "\n非常感谢成为劉員外会员.请及时更新密码!");
    sb.append("\n");
    sb.append("官方网址：www.liuyuanwai.cn");
    e.setContent(sb.toString());
    emailHandler.asyncSendMail(e);
    return gson.toJson(HttpResponse.create(Codes.OK));
  }


  // - 得到数据库没有的推荐码
  public String getUniqueUnUsedReferralCode(String referralCode, List<String> codes) {
    if (CollectionUtils.isEmpty(codes)) {
      return referralCode;
    }
    if (!codes.contains(referralCode)) {
      // - 该推荐码没有被使用
      return referralCode;
    }
    return getUniqueUnUsedReferralCode(RandomUtils.random6(), codes);
  }

  public boolean isReferralCodeExists(String referralCode, List<String> codes) {
    if (CollectionUtils.isEmpty(codes)) {
      return Boolean.FALSE;
    }
    if (codes.contains(referralCode)) {
      return Boolean.TRUE;
    }
    return Boolean.FALSE;
  }

  // - 登录
  @Override
  public Object login(String email, String password) {

    ShCompany shCompany = companyMapper.queryByEmail(email);
    if (shCompany == null) {
      throw BizException.create(Codes.LoginError, "邮箱不存在");
    }
    shCompany = companyMapper.login(email, EncryptUtils.md5(password));
    if (shCompany == null) {
      throw BizException.create(Codes.LoginError, "帐号密码验证失败");
    }
    sessionLoginInfo(shCompany);
    return gson.toJson(HttpResponse.create(Codes.OK, "", shCompany));
  }

  // - 将户相关信息写到session
  private void sessionLoginInfo(ShCompany shCompany) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
      .getRequestAttributes()).getRequest();
    // - 将用户邮箱存到session
    request.getSession().setAttribute("email", shCompany.getEmail());
    // - 将用户角色存入session
    request.getSession().setAttribute("roleId", shCompany.getRole());
    // - 将用户LOGO存入session
    request.getSession().setAttribute("logo", shCompany.getLogo());
    // - 将用户NAME存入session
    request.getSession().setAttribute("name", shCompany.getName());
  }

  @Override
  public Object fakeLogin(String email, String login) {
    if (StringUtils.isBlank(email) || StringUtils.isBlank(login)) {
      return gson.toJson(HttpResponse.create(Codes.LoginError));
    }
    ShCompany company = companyMapper.queryByEmail(email);
    if (company == null) {
      return gson.toJson(HttpResponse.create(Codes.LoginError));
    }
    sessionLoginInfo(company);
    return gson.toJson(HttpResponse.create(Codes.OK, "", company));
  }

  /**
   * 查询企业资料
   *
   * @param email
   * @return
   */
  @Override
  public UserExtDto info(String email) {

    ShCompany shCompany = companyMapper.queryByEmail(email);
    if (shCompany == null) {
      throw BizException.create(Codes.SystemDeclare, "没有查询到用户");
    }
    shCompany.setRole(RoleEnum.queryStatusVal(Integer.valueOf(shCompany.getRole())));
    if (StringUtils.isBlank(shCompany.getRemark())) {
      shCompany.setRemark("简介");
    }
    UserExtDto userExtDto = new UserExtDto();
    BeanUtils.copyProperties(shCompany, userExtDto);
    ShSet set = setMapper.queryByEmail(email);
    if (set != null) {
      userExtDto.setStoryNotify(set.getStoryNotify());
      userExtDto.setNoteNotify(set.getNoteNotify());
    } else {
      userExtDto.setStoryNotify(1);
      userExtDto.setNoteNotify(1);
    }
    return userExtDto;
  }

  /**
   * 查询企业资料.只读
   *
   * @param email
   * @return
   */
  @Override
  public UserExtDto queryInfo(String email) {
    UserExtDto userExtDto = new UserExtDto();
    ShCompany shCompany = companyMapper.queryUserExtByEmail(email);
    if (shCompany == null) {
      return userExtDto;
    }
    BeanUtils.copyProperties(shCompany, userExtDto);
    BigDecimal income = incomeWaterMapper.calculateMyIncome(email, null);
    if (income == null) {
      income = BigDecimal.ZERO.setScale(2);
    }
    userExtDto.setIncome(income);
    return userExtDto;
  }

  /**
   * 更新资料
   *
   * @param shCompany
   * @return
   */
  @Override
  public Object updateInfo(ShCompany shCompany) {

    if (shCompany == null) {
      throw BizException.create(Codes.ParamError, "空参数");
    }

    if (StringUtils.isBlank(shCompany.getPhone())) {
      throw BizException.create(Codes.ParamError, "请填写手机号");
    }
    if (!ValidatorUtils.validatorMobile(shCompany.getPhone())) {
      throw BizException.create(Codes.ParamError, "手机号格式错误");
    }

    shCompany.setDeleted(0);
    shCompany.setCheckStatus(0);
    shCompany.setUpdatetime(new Date());
    // - 修改资料后审核状态改为等待审核
    shCompany.setCheckStatus(0);
    companyMapper.saveOrUpdate(shCompany);
    // - 更新session数据
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    request.getSession().setAttribute("name", shCompany.getName());
    return gson.toJson(HttpResponse.OK());
  }


  /**
   * 更新密码
   *
   * @param password
   * @param email
   * @return
   */
  @Override
  public Object updatePassword(String password, String email, String oldPassword) {
    ShCompany shCompany = companyMapper.login(email, EncryptUtils.md5(oldPassword));
    if (shCompany == null) {
      throw BizException.create(Codes.SystemDeclare, "旧密码验证失败");
    }
    companyMapper.updatePassword(EncryptUtils.md5(password), email, EncryptUtils.md5(oldPassword), new Date());
    return gson.toJson(HttpResponse.OK());
  }


  /**
   * 分页查询所有用户
   *
   * @param page
   * @param limit
   * @return
   */
  @Override
  public Object list(int page, int limit, String queryKey, String role) {
    if (page > 0) {
      page = page - 1;
    }
    if (StringUtils.isBlank(role)) {
      role = null;
    }
    UserSortDto userSortDto = new UserSortDto();
    int count = companyMapper.count(queryKey, role);
    List<ShCompany> companies = companyMapper.list(page * limit, limit, queryKey, role);
    for (ShCompany shCompany : companies) {
      shCompany.setRole(RoleEnum.queryStatusVal(Integer.valueOf(shCompany.getRole())));
      if (StringUtils.isBlank(shCompany.getRemark())) {
        shCompany.setRemark("简介");
      }
    }
    Paginator paginator = Paginator.instance(count, companies);
    paginator.setPage(page + 1);
    paginator.setLimit(limit);
    userSortDto.setPaginator(paginator);
    return userSortDto;
  }

  /**
   * 审核
   *
   * @param ids    审核用户ID集合，逗号分割
   * @param status 审核结果【1：审核通过，2：审核失败】
   * @return
   */
  @Override
  public Object check(String ids, Integer status) {
    if (StringUtils.isBlank(ids)) {
      return HttpResponse.OK();
    }
    companyMapper.check(ids.split(","), status);
    return HttpResponse.OK();
  }


  /**
   * 找回密码，用一个随机的四位数作为新密码
   *
   * @param email
   * @return
   */
  @Override
  public Object findPassword(String email) {

    boolean flag = ValidatorUtils.validatorEmail(email);
    if (!flag) {
      throw BizException.create(Codes.ParamError, "邮箱格式错误");
    }
    ShCompany shCompany = companyMapper.queryByEmail(email);
    if (shCompany == null) {
      throw BizException.create(Codes.ParamError, "邮箱不存在");
    }

    String password = RandomUtils.random4();
    companyMapper.updatePassword(EncryptUtils.md5(password), email, null, new Date());

    // - 异步发邮件
    Email e = new Email();
    String[] to = new String[1];
    to[0] = email;
    e.setTo(to);
    e.setSubject("密码找回");
    e.setContent("新密码:" + password + ".请及时更新密码!\n官方网址：www.liuyuanwai.cn");

    e.setEnableHtml(Boolean.FALSE);
    emailHandler.asyncSendMail(e);
    return gson.toJson(HttpResponse.create(Codes.OK, "密码已发送至邮箱"));
  }

  @Override
  public Object updateUserRole(String email, Integer roleId) {
    companyMapper.updateUserRole(email, roleId);
    return HttpResponse.OK();
  }


  @Override
  public Object updateLogo(String logo, String email) {
    companyMapper.updateLogo(logo, email);
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    request.getSession().setAttribute("logo", logo);
    return HttpResponse.OK();
  }

  @Override
  public void updateInCount() {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    Object email = request.getSession().getAttribute("email");
    if (email != null) {
      companyMapper.incrInCount(email.toString());
    }
  }

  @Override
  public Object warterStatistic() {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    Object email = request.getSession().getAttribute("email");
    Map<String/* day */, BigDecimal/* amount */> platMap = Maps.newHashMap();
    Map<String/* day */, BigDecimal/* amount */> selfMap = Maps.newHashMap();
    List<String> xAixs = Lists.newArrayList();
    // - 平台流水
    List<BigDecimal> platWateryAixs = Lists.newArrayList();
    // - 我的流水
    List<BigDecimal> selfWateryAixs = Lists.newArrayList();
    int curDay = DateUtils.getDay();
    int j = 0;
    int lastDayOfLastMonth = DateUtils.getLastDayOfLastMonth();
    for (int i = curDay - 9; i <= curDay; i++) {
      j = i;
      if (j <= 0) {
        j += lastDayOfLastMonth;
      }
      xAixs.add(String.valueOf(j));
      platMap.put(String.valueOf(j), BigDecimal.ZERO);
      selfMap.put(String.valueOf(j), BigDecimal.ZERO);
    }
    List<StatisticOutputDto> platWater = companyMapper.searchConsumptionWarter(null);
    if (!CollectionUtils.isEmpty(platWater)) {
      for (StatisticOutputDto statisticOutputDto : platWater) {
        platMap.put(statisticOutputDto.getName(), statisticOutputDto.getData());
      }
      for (String x : xAixs) {
        platWateryAixs.add(platMap.get(x));
      }
    } else {
      for (int i = curDay - 9; i <= curDay; i++) {
        platWateryAixs.add(BigDecimal.ZERO);
      }
    }
    List<StatisticOutputDto> selfWater = null;
    if (email != null) {
      selfWater = companyMapper.searchConsumptionWarter(email.toString());
      if (!CollectionUtils.isEmpty(selfWater)) {
        for (StatisticOutputDto statisticOutputDto : selfWater) {
          selfMap.put(statisticOutputDto.getName(), statisticOutputDto.getData());
        }
        for (String x : xAixs) {
          selfWateryAixs.add(selfMap.get(x));
        }
      } else {
        for (int i = curDay - 9; i <= curDay; i++) {
          selfWateryAixs.add(BigDecimal.ZERO);
        }
      }
    }
    ConsumptionWaterDto consumptionWaterDto = new ConsumptionWaterDto();
    consumptionWaterDto.setxAixs(xAixs);
    consumptionWaterDto.setPlatWateryAixs(platWateryAixs);
    consumptionWaterDto.setSelfWateryAixs(selfWateryAixs);
    return consumptionWaterDto;
  }

  @Override
  public Object userStatistic() {
    List<StatisticOutputDto> list = companyMapper.userStatistic();
    UserStatisticDto dto = new UserStatisticDto();
    List<String> xAixs = Lists.newArrayList();
    List<Integer> yAixs = Lists.newArrayList();
    Map<String, Integer> map = Maps.newHashMap();
    int curDay = DateUtils.getDay();
    int j = 0;
    int lastDayOfLastMonth = DateUtils.getLastDayOfLastMonth();
    for (int i = curDay - 9; i <= curDay; i++) {
      j = i;
      if (j <= 0) {
        j += lastDayOfLastMonth;
      }
      xAixs.add(String.valueOf(j));
      map.put(String.valueOf(j), 0);
    }
    if (!CollectionUtils.isEmpty(list)) {
      for (StatisticOutputDto outputDto : list) {
        map.put(outputDto.getName(), Integer.parseInt(outputDto.getData().toString()));
      }
    }
    int max = companyMapper.count(null, null);
    int min = Collections.min(map.values());
    for (String xAix : xAixs) {
      yAixs.add(map.get(xAix));
    }
    if (yAixs.get(0) < min) {
      yAixs.set(0, min);
    }
    if (yAixs.get(yAixs.size() - 1) < max) {
      yAixs.set(yAixs.size() - 1, max);
    }
    for (int i = 0; i < yAixs.size() - 1; i++) {
      if (yAixs.get(i + 1) < yAixs.get(i)) {
        yAixs.set(i + 1, yAixs.get(i));
      }
    }
    for (int i = yAixs.size(); i > 0; i--) {
      if (yAixs.get(i - 1) == 0) {
        yAixs.set(i - 1, yAixs.get(i));
      }
    }
    dto.setxAixs(xAixs);
    dto.setyAixs(yAixs);
    return dto;
  }

  @Override
  public Object platStatistic(String shopEmail) {
    Map<String/* day */, BigDecimal/* amount */> platWaterMap = Maps.newHashMap();
    Map<String/* day */, BigDecimal/* amount */> platCostMap = Maps.newHashMap();
    Map<String/* day */, BigDecimal/* amount */> platIncomeMap = Maps.newHashMap();
    List<String> xAixs = Lists.newArrayList();
    // - 平台流水
    List<BigDecimal> platWateryAixs = Lists.newArrayList();
    // - 平台成本
    List<BigDecimal> platCostyAixs = Lists.newArrayList();
    // - 平台收益
    List<BigDecimal> platIncomeyAixs = Lists.newArrayList();
    int curDay = DateUtils.getDay();
    int j = 0;
    int lastDayOfLastMonth = DateUtils.getLastDayOfLastMonth();
    for (int i = curDay - 9; i <= curDay; i++) {
      j = i;
      if (j <= 0) {
        j += lastDayOfLastMonth;
      }
      xAixs.add(String.valueOf(j));
      platWaterMap.put(String.valueOf(j), BigDecimal.ZERO);
      platCostMap.put(String.valueOf(j), BigDecimal.ZERO);
      platIncomeMap.put(String.valueOf(j), BigDecimal.ZERO);
    }
    List<StatisticOutputDto> platData = null;
    if (StringUtils.isBlank(shopEmail)) {
      // - 平台消费流水
      platData = companyMapper.searchConsumptionWarter(null);
    } else {
      // - 门店消费流水
      platData = companyMapper.searchShopWarter(shopEmail);
    }
    if (!CollectionUtils.isEmpty(platData)) {
      for (StatisticOutputDto statisticOutputDto : platData) {
        platWaterMap.put(statisticOutputDto.getName(), statisticOutputDto.getData());
        platCostMap.put(statisticOutputDto.getName(), statisticOutputDto.getData1());
        platIncomeMap.put(statisticOutputDto.getName(), statisticOutputDto.getData().subtract(statisticOutputDto.getData1()));
      }
      for (String x : xAixs) {
        platWateryAixs.add(platWaterMap.get(x));
        platCostyAixs.add(platCostMap.get(x));
        platIncomeyAixs.add(platIncomeMap.get(x));
      }
    } else {
      for (int i = curDay - 9; i <= curDay; i++) {
        platWateryAixs.add(BigDecimal.ZERO);
        platCostyAixs.add(BigDecimal.ZERO);
        platIncomeyAixs.add(BigDecimal.ZERO);
      }
    }
    ConsumptionWaterDto consumptionWaterDto = new ConsumptionWaterDto();
    consumptionWaterDto.setxAixs(xAixs);
    consumptionWaterDto.setPlatWateryAixs(platWateryAixs);
    consumptionWaterDto.setPlatCostyAixs(platCostyAixs);
    consumptionWaterDto.setPlatIncomeyAixs(platIncomeyAixs);
    // - 计算平台总流水和总收益
    BigDecimal water = BigDecimal.ZERO;
    BigDecimal cost = BigDecimal.ZERO;
    if (StringUtils.isBlank(shopEmail)) {
      // - 平台
      water = orderMapper.waterStatistic();
      cost = orderMapper.costStatistic();
    } else {
      // - 门店
      water = orderMapper.shopWaterStatistic(shopEmail);
      cost = orderMapper.shopCostStatistic(shopEmail);
    }
    if (water == null) {
      water = BigDecimal.ZERO;
    }
    if (cost == null) {
      cost = BigDecimal.ZERO;
    }
    consumptionWaterDto.setPlatWater(water.setScale(2, BigDecimal.ROUND_HALF_UP));
    consumptionWaterDto.setPlatCost(cost.setScale(2, BigDecimal.ROUND_HALF_UP));
    consumptionWaterDto.setPlatIncome(consumptionWaterDto.getPlatWater().subtract(consumptionWaterDto.getPlatCost()));
    return consumptionWaterDto;
  }

  @Override
  public BigDecimal incomeStatistic(String email, Integer deleted) {
    if (StringUtils.isBlank(email)) {
      HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
      Object obj = request.getSession().getAttribute("email");
      if (obj != null) {
        email = obj.toString();
      }
    }
    BigDecimal income = companyMapper.queryByEmail(email).getInCount();
    if (income == null) {
      return BigDecimal.ZERO;
    }
    return income;
  }

  @Override
  public BigDecimal incomeSingleStatistic(String buyerEmail, String shopEmail) {
    BigDecimal income = incomeWaterMapper.calculateSingleIncome(buyerEmail, shopEmail);
    if (income == null) {
      income = BigDecimal.ZERO;
    }
    return income;
  }

  @Override
  public Object incomeList(int pageNo, int pageSize, Integer shopId) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    String email = null;
    Object obj = request.getSession().getAttribute("email");
    if (obj != null) {
      email = obj.toString();
    }
    if (pageNo > 0) {
      pageNo = pageNo - 1;
    }
    List<ShIncomeWater> list = incomeWaterMapper.list(email, pageNo * pageSize, pageSize, shopId);
    return Paginator.instance(0, list);
  }

  @Override
  public Object incomeListGroupByShop(int pageNo, int pageSize) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    String email = null;
    Object obj = request.getSession().getAttribute("email");
    if (obj != null) {
      email = obj.toString();
    }
    if (pageNo > 0) {
      pageNo = pageNo - 1;
    }
    List<ShIncomeWater> list = incomeWaterMapper.listIncomeGroupByShop(email, pageNo * pageSize, pageSize);
    return list;
  }


  @Override
  public Object updateWeixinQrcode(String weixinQrcode, String email) {
    companyMapper.updateWeixinQrcode(weixinQrcode, email);
    return HttpResponse.OK();
  }

  @Override
  public Object updateAlipayQrcode(String alipayQrcode, String email) {
    companyMapper.updateAlipayQrcode(alipayQrcode, email);
    return HttpResponse.OK();
  }

  @Override
  public void validateUserInfoCompleted(String email) {
    ShCompany company = companyMapper.queryByEmail(email);
    if (company == null) {
      throw BizException.create(Codes.SystemDeclare, "没有查询到您的资料");
    }
    if (StringUtils.isBlank(company.getName())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:姓名");
    }
    if (StringUtils.isBlank(company.getPhone())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:电话");
    }
    if (StringUtils.isBlank(company.getAddr())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:联系地址");
    }
    if (StringUtils.isBlank(company.getLogo())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:头像");
    }
  }

  @Override
  public void validateUserInfoCompleted(ShCompany company) {
    if (company == null) {
      throw BizException.create(Codes.SystemDeclare, "没有查询到您的资料");
    }
    if (StringUtils.isBlank(company.getName())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:姓名");
    }
    if (StringUtils.isBlank(company.getPhone())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:电话");
    }
    if (StringUtils.isBlank(company.getAddr())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:联系地址");
    }
    if (StringUtils.isBlank(company.getLogo())) {
      throw BizException.create(Codes.SystemDeclare, "请完善资料:头像");
    }
  }
}
